#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Gezel.Simulator.Reference
{
  /// <summary>
  /// The datapath object is the runtime representation
  /// of a Gezel datapath. Foreach cycle the datapath
  /// runs by evaluating its output ports and its
  /// registers. Tracking which signalflowgraphs are
  /// activated for a particular simulation cycle is
  /// deferred to the DatapathContext object used by
  /// the SignalContext to determine signal drivers.
  /// </summary>
  class Datapath
  {
    /// <summary>
    /// Id of the datapath
    /// </summary>
    private readonly Symid id;

    /// <summary>
    /// Fully qualified name of this
    /// datapath
    /// </summary>
    private string name;
    public string Name
    {
      get
      {
        return name;
      }
    }

    /// <summary>
    /// The list of output ports on this datapath
    /// </summary>
    private List<OutputSignal> outputs;

    /// <summary>
    /// The list of input ports on this datapath
    /// </summary>
    private List<InputSignal> inputs;

    /// <summary>
    /// The list of registers contained by
    /// this datapath
    /// </summary>
    private List<RegisterSignal> registers;

    /// <summary>
    /// The list of child datapaths contained by this datapath
    /// </summary>
    private List<Datapath> childDatapaths;

		/// <summary>
		/// List of child ip blocks contained by this datapath
		/// </summary>
		private List<AbstractIpBlock> ipBlocks;

    /// <summary>
    /// Datapath context associated with this datapath is
    /// internally visible
    /// </summary>
    internal readonly DatapathContext datapathContext;

    /// <summary>
    /// Constructs a new datapath with the given id and
    /// fully qualified name and initializes its internal
    /// datastructures
    /// </summary>
    /// <param name="v">id of the datapath</param>
    /// <param name="name">fully qualified name</param>
    public Datapath(Symid v, string name)
    {
      this.id = v;
      this.name = name;

      this.datapathContext = new DatapathContext();
			this.ipBlocks = new List<AbstractIpBlock>();
      this.outputs = new List<OutputSignal>();
      this.inputs = new List<InputSignal>();
      this.registers = new List<RegisterSignal>();
      this.childDatapaths = new List<Datapath>();
    }

    /// <summary>
    /// Adds a new input port to the datapath
    /// </summary>
    /// <param name="v"></param>
    internal void appendInput(InputSignal v)
    {
      inputs.Add(v);
    }

    /// <summary>
    /// Adds a new child datapath datapath
    /// </summary>
    /// <param name="v"></param>
    internal void appendChildDatapath(Datapath datapath)
    {
      childDatapaths.Add(datapath);
    }

		/// <summary>
		/// Adds a new child ip block to the datapath
		/// </summary>
		/// <param name="ipBlock"></param>
		internal void appendChildIpBlock(AbstractIpBlock ipBlock)
		{
			ipBlocks.Add(ipBlock);
		}

    /// <summary>
    /// Adds a new output port to the datapath
    /// </summary>
    /// <param name="v"></param>
    internal void appendOutput(OutputSignal v)
    {
      outputs.Add(v);
    }

    /// <summary>
    /// Makes the dapapath evaluate its contents for
    /// this cycle, by evaluating all its outputs and
    /// subsequently updating its registers
    /// </summary>
    /// <param name="g"></param>
    public void Evaluate(long g)
    {
      // normal simulation
      foreach (OutputSignal output in outputs)
      {
        try
        {
          output.Evaluate(null, g);
        }
        catch (CombinatorialLoopException cle)
        {
          List<AbstractSignal> signals = new List<AbstractSignal>();

          // TODO: trace will cause a stackoverflow .. why?
      
              //output.TraceToSignal(cle.SignalId, signals);
              //cle.Signals = signals;

              //Console.WriteLine("Signals: " + cle.Signals.Count);


          throw cle;
        }
      }

      foreach (RegisterSignal reg in registers)
      {
        reg.UpdateIn(g);
      }

    }

    /// <summary>
    /// Updates the values of the registers at the
    /// end of the simulation cycle
    /// </summary>
    public void Tick()
    {
      foreach (RegisterSignal reg in registers)
      {
        reg.Tick();
      }
    }

    /// <summary>
    /// Returns true iff the referenced signalflowgraph
    /// is active in the current simulation cycle
    /// </summary>
    /// <param name="sfgId">id of the signalflowgraph</param>
    /// <returns></returns>
    public bool IsSignalFlowGraphActive(Symid sfgId)
    {
      return datapathContext.IsSignalFlowGraphActive(sfgId);
    }

    /// <summary>
    /// Adds a register to the datapath
    /// </summary>
    /// <param name="v"></param>
    public void appendRegister(RegisterSignal v)
    {
      registers.Add(v);
    }

    /// <summary>
    /// Adds a child datapath to this datapath
    /// </summary>
    /// <param name="v"></param>
    public void appendDatapath(Datapath childDatapath)
    {
      childDatapaths.Add(childDatapath);
    }
  }
}